/*********************************************************************************************************************
版权所有 (C), 2021,
设计：山亦青
编码：山亦青
版本：V1.0.0.0
完成日期：2021.4.1
说明:
 虚拟标准键盘的源文件
代码级别：u
*********************************************************************************************************************/

#include "VirtualKeyboard.h"

#define VK_CHAR_KEY_LEN 45 //键盘每个字符按键的边长
#define VK_CHAR_KEY_MARGIN 5 //每个字符的左上边距
#define VK_LINE_LEN (VK_CHAR_KEY_LEN + VK_CHAR_KEY_MARGIN) //键盘每一行的高度
#define VK_WIDTH (13 * VK_LINE_LEN) //整个虚拟键盘的宽度
#define VK_HEIGHT (6 * VK_LINE_LEN) //整个虚拟键盘的高度
#define VK_HINT_MARGIN_LEFT 20 //虚拟键盘提示文字的左边距
#define VK_HINT_LABEL_WIDTH (VK_WIDTH / 2 - VK_HINT_MARGIN_LEFT) //提示文字的宽度

// 初始化字符按键的宏，参数分别为按键的下标、字符、左边距、上边距
#define INIT_CHAR_KEY(index, character, left, top) \
    m_CharKeys[index].setParent(this); \
    m_CharKeys[index].setFontSize(12); \
    m_CharKeys[index].setText(tr(character)); \
    m_CharKeys[index].setBorderRadius(5); \
    m_CharKeys[index].setGeometry(left + 5, top, VK_CHAR_KEY_LEN, VK_CHAR_KEY_LEN); \
    connect(&m_CharKeys[index], \
        SIGNAL(onMouseClick(const GradientButton*)), \
        this, \
        SLOT(onCharacterKeyDown(const GradientButton*)))

VirtualKeyboard::VirtualKeyboard() :
    m_Case(VK_ALLOW_BIG_LETTER | VK_ALLOW_SMALL_LETTER), //大小写限制
    m_IsPwd(Bool_false), //是否为密码
    m_InputMaxLen(VK_INPUT_INFI),
    m_InitValue(tr("")), //初始值
    m_InputValue(tr("")), //输入值
    m_FieldName(tr("")), //字段名
    m_CurrentIsSmall(Bool_true), //当前是否为小写
    m_FieldLabel(this),
    m_ValueLabel(this)
{
    // 模式对话框
    this->setModal(Bool_true);

    // 不显示标题栏
    setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);

    //不可拉动宽高度
    setSizeGripEnabled(Bool_false);

    // 最上方的label
    m_FieldLabel.setGeometry(VK_HINT_MARGIN_LEFT, 0, VK_HINT_LABEL_WIDTH, VK_LINE_LEN);
    m_ValueLabel.setGeometry(VK_HINT_MARGIN_LEFT + VK_WIDTH / 2, 0, VK_HINT_LABEL_WIDTH, VK_LINE_LEN);

    // 给label上色
    QPalette labelPal;
    labelPal.setColor(QPalette::WindowText, Qt::white);
    m_FieldLabel.setPalette(labelPal);
    m_ValueLabel.setPalette(labelPal);

    // 配置按键
    // 第一排的数字键
    INIT_CHAR_KEY(0, "0", 0, VK_LINE_LEN);
    INIT_CHAR_KEY(1, "1", VK_LINE_LEN, VK_LINE_LEN);
    INIT_CHAR_KEY(2, "2", 2 * VK_LINE_LEN, VK_LINE_LEN);
    INIT_CHAR_KEY(3, "3", 3 * VK_LINE_LEN, VK_LINE_LEN);
    INIT_CHAR_KEY(4, "4", 4 * VK_LINE_LEN, VK_LINE_LEN);
    INIT_CHAR_KEY(5, "5", 5 * VK_LINE_LEN, VK_LINE_LEN);
    INIT_CHAR_KEY(6, "6", 6 * VK_LINE_LEN, VK_LINE_LEN);
    INIT_CHAR_KEY(7, "7", 7 * VK_LINE_LEN, VK_LINE_LEN);
    INIT_CHAR_KEY(8, "8", 8 * VK_LINE_LEN, VK_LINE_LEN);
    INIT_CHAR_KEY(9, "9", 9 * VK_LINE_LEN, VK_LINE_LEN);

    // 第二排，以'q'起始的字母按键
    INIT_CHAR_KEY(10, "q", 0, 2 * VK_LINE_LEN);
    INIT_CHAR_KEY(11, "w", VK_LINE_LEN, 2 * VK_LINE_LEN);
    INIT_CHAR_KEY(12, "e", 2 * VK_LINE_LEN, 2 * VK_LINE_LEN);
    INIT_CHAR_KEY(13, "r", 3 * VK_LINE_LEN, 2 * VK_LINE_LEN);
    INIT_CHAR_KEY(14, "t", 4 * VK_LINE_LEN, 2 * VK_LINE_LEN);
    INIT_CHAR_KEY(15, "y", 5 * VK_LINE_LEN, 2 * VK_LINE_LEN);
    INIT_CHAR_KEY(16, "u", 6 * VK_LINE_LEN, 2 * VK_LINE_LEN);
    INIT_CHAR_KEY(17, "i", 7 * VK_LINE_LEN, 2 * VK_LINE_LEN);
    INIT_CHAR_KEY(18, "o", 8 * VK_LINE_LEN, 2 * VK_LINE_LEN);
    INIT_CHAR_KEY(19, "p", 9 * VK_LINE_LEN, 2 * VK_LINE_LEN);

    // 第三排，以'a'为起始的字母按键
    INIT_CHAR_KEY(20, "a", VK_LINE_LEN / 2, 3 * VK_LINE_LEN);
    INIT_CHAR_KEY(21, "s", VK_LINE_LEN / 2 * 3, 3 * VK_LINE_LEN);
    INIT_CHAR_KEY(22, "d", VK_LINE_LEN / 2 * 5, 3 * VK_LINE_LEN);
    INIT_CHAR_KEY(23, "f", VK_LINE_LEN / 2 * 7, 3 * VK_LINE_LEN);
    INIT_CHAR_KEY(24, "g", VK_LINE_LEN / 2 * 9, 3 * VK_LINE_LEN);
    INIT_CHAR_KEY(25, "h", VK_LINE_LEN / 2 * 11, 3 * VK_LINE_LEN);
    INIT_CHAR_KEY(26, "j", VK_LINE_LEN / 2 * 13, 3 * VK_LINE_LEN);
    INIT_CHAR_KEY(27, "k", VK_LINE_LEN / 2 * 15, 3 * VK_LINE_LEN);
    INIT_CHAR_KEY(28, "l", VK_LINE_LEN / 2 * 17, 3 * VK_LINE_LEN);

    // 第四排，以'z'起始的字母按键
    INIT_CHAR_KEY(29, "z", VK_LINE_LEN, 4 * VK_LINE_LEN);
    INIT_CHAR_KEY(30, "x", 2 * VK_LINE_LEN, 4 * VK_LINE_LEN);
    INIT_CHAR_KEY(31, "c", 3 * VK_LINE_LEN, 4 * VK_LINE_LEN);
    INIT_CHAR_KEY(32, "v", 4 * VK_LINE_LEN, 4 * VK_LINE_LEN);
    INIT_CHAR_KEY(33, "b", 5 * VK_LINE_LEN, 4 * VK_LINE_LEN);
    INIT_CHAR_KEY(34, "n", 6 * VK_LINE_LEN, 4 * VK_LINE_LEN);
    INIT_CHAR_KEY(35, "m", 7 * VK_LINE_LEN, 4 * VK_LINE_LEN);

    // 第五排，最大的空格键
    m_CharKeys[36].setParent(this);
    m_CharKeys[36].setFontSize(12);
    m_CharKeys[36].setText(QCHNTXT(" "));
    m_CharKeys[36].setBorderRadius(5);
    m_CharKeys[36].setGeometry(2 * VK_LINE_LEN, 5 * VK_LINE_LEN, 6 * VK_CHAR_KEY_LEN, VK_CHAR_KEY_LEN);
    connect(&m_CharKeys[36],
        SIGNAL(onMouseClick(const GradientButton*)),
        this,
        SLOT(onCharacterKeyDown(const GradientButton*)));

    // 大小写切换键
    m_ShiftKey.setParent(this);
    m_ShiftKey.setFontSize(12);
    m_ShiftKey.setText(QCHNTXT("abc"));
    m_ShiftKey.setBorderRadius(5);
    m_ShiftKey.setGeometry(5, 5 * VK_LINE_LEN, 2 * VK_CHAR_KEY_LEN, VK_CHAR_KEY_LEN);
    connect(&m_ShiftKey,
        SIGNAL(onMouseClick(const GradientButton*)),
        this,
        SLOT(onShiftKeyDown(const GradientButton*)));

    // 退格键
    m_BackSpaceKey.setParent(this);
    m_BackSpaceKey.setFontSize(12);
    m_BackSpaceKey.setText(QCHNTXT("删除"));
    m_BackSpaceKey.setBorderRadius(5);
    m_BackSpaceKey.setGeometry(11 * VK_LINE_LEN, VK_LINE_LEN, 2 * VK_CHAR_KEY_LEN, VK_CHAR_KEY_LEN);
    connect(&m_BackSpaceKey,
        SIGNAL(onMouseClick(const GradientButton*)),
        this,
        SLOT(onBackSpaceKeyDown(const GradientButton*)));

    // 清空键
    m_ClearInputKey.setParent(this);
    m_ClearInputKey.setFontSize(12);
    m_ClearInputKey.setText(QCHNTXT("清空"));
    m_ClearInputKey.setBorderRadius(5);
    m_ClearInputKey.setGeometry(11 * VK_LINE_LEN, 2 * VK_LINE_LEN, 2 * VK_CHAR_KEY_LEN, VK_CHAR_KEY_LEN);
    connect(&m_ClearInputKey,
        SIGNAL(onMouseClick(const GradientButton*)),
        this,
        SLOT(onClearKeyDown(const GradientButton*)));

    // 确认
    m_OKKey.setParent(this);
    m_OKKey.setFontSize(12);
    m_OKKey.setText(QCHNTXT("确认"));
    m_OKKey.setBorderRadius(5);
    m_OKKey.setGeometry(11 * VK_LINE_LEN, 3 * VK_LINE_LEN, 2 * VK_CHAR_KEY_LEN, VK_CHAR_KEY_LEN);
    connect(&m_OKKey,
        SIGNAL(onMouseClick(const GradientButton*)),
        this,
        SLOT(onOK(const GradientButton*)));

    // 取消
    m_CancelKey.setParent(this);
    m_CancelKey.setFontSize(12);
    m_CancelKey.setText(QCHNTXT("取消"));
    m_CancelKey.setBorderRadius(5);
    m_CancelKey.setGeometry(11 * VK_LINE_LEN, 4 * VK_LINE_LEN, 2 * VK_CHAR_KEY_LEN, VK_CHAR_KEY_LEN);
    connect(&m_CancelKey,
        SIGNAL(onMouseClick(const GradientButton*)),
        this,
        SLOT(onCancel(const GradientButton*)));
}

Void_t VirtualKeyboard::paintEvent(QPaintEvent*)
{}

// 设置大小写使能
// 参数1：caseToSet，是否允许大小写，由VK_ALLOW_BIG_LETTER和VK_ALLOW_SMALL_LETTER，
Void_t VirtualKeyboard::setCase(Int32_t caseToSet)
{
    m_Case = caseToSet;
}

// 设置是否为密码
// 参数1：isPassword，是否为密码，默认是false
Void_t VirtualKeyboard::setPassword(Bool_t isPassword)
{
    m_IsPwd = isPassword;
}

// 设置长度上限
// 参数1：要设置的长度值，特殊值为VK_INPUT_INFI，表示无限长度
Void_t VirtualKeyboard::setMaxLength(Int32_t len)
{
    m_InputMaxLen = len;
}

// 设置初始值
// 参数1：initValue，初始值，默认为空字符串
Void_t VirtualKeyboard::setInitValue(Constant QString& initValue)
{
    m_InitValue = initValue;
}

// 设置字段名
// 参数1：filedName，字段名，默认空字符串
Void_t VirtualKeyboard::setFieldName(Constant QString& fieldName)
{
    m_FieldName = fieldName;
}

// 显示模式对话框
// 参数1：left，父级组件的左边距
// 参数2：top，父级组件的上边距
Void_t VirtualKeyboard::doModal(Length_t left, Length_t top)
{
    // 整个虚拟键盘的宽高度
    QRect rect(left, top, VK_WIDTH, VK_HEIGHT);
    setGeometry(rect);

    // 画背景图
    this->setAutoFillBackground(true);
    QPalette palette;// = this->palette();
    QPixmap img = QPixmap("Images/6.png");
    palette.setBrush(QPalette::Background,
                     QBrush(img.scaled(this->size(),
                     Qt::IgnoreAspectRatio,
                     Qt::SmoothTransformation)));// 使用平滑的缩放方式
    this->setPalette(palette);// 给widget加上背景图

    // 更新大小写
    if (VK_ALLOW_SMALL_LETTER == m_Case)
    {
        // 如果只允许小写输入，把大小写切换键disable掉，并且把当前模式切换为小写
        m_CurrentIsSmall = Bool_true;
        m_ShiftKey.setDisabled(Bool_true);
    }
    else if (VK_ALLOW_BIG_LETTER == m_Case)
    {
        // 如果只允许大写输入，把大小写切换键disable掉，并且把当前模式切换为大写
        m_CurrentIsSmall = Bool_false;
        m_ShiftKey.setDisabled(Bool_true);
    }
    else if ((VK_ALLOW_SMALL_LETTER | VK_ALLOW_BIG_LETTER) == m_Case)
    {
        // 如果是大小写输入都允许，那么默认采用小写输入
        m_CurrentIsSmall = Bool_true;
    }

    // 更新大小写
    updateLetters();

    // 赋初值
    m_InputValue = m_InitValue;
    if (m_FieldName.length() > 0)
    {
        m_FieldLabel.setText(m_FieldName);
    }
    updateInputValue();
    exec();
}

Void_t VirtualKeyboard::updateLetters()
{
    // 大小写切换键
    m_ShiftKey.setText(QCHNTXT(m_CurrentIsSmall ? "abc" : "ABC"));

    // 第二排，以'q'起始的字母按键
    m_CharKeys[10].setText(tr(m_CurrentIsSmall ? "q" : "Q"));
    m_CharKeys[11].setText(tr(m_CurrentIsSmall ? "w" : "W"));
    m_CharKeys[12].setText(tr(m_CurrentIsSmall ? "e" : "E"));
    m_CharKeys[13].setText(tr(m_CurrentIsSmall ? "r" : "R"));
    m_CharKeys[14].setText(tr(m_CurrentIsSmall ? "t" : "T"));
    m_CharKeys[15].setText(tr(m_CurrentIsSmall ? "y" : "Y"));
    m_CharKeys[16].setText(tr(m_CurrentIsSmall ? "u" : "U"));
    m_CharKeys[17].setText(tr(m_CurrentIsSmall ? "i" : "I"));
    m_CharKeys[18].setText(tr(m_CurrentIsSmall ? "o" : "O"));
    m_CharKeys[19].setText(tr(m_CurrentIsSmall ? "p" : "P"));

    // 第三排，以'a'为起始的字母按键
    m_CharKeys[20].setText(tr(m_CurrentIsSmall ? "a" : "A"));
    m_CharKeys[21].setText(tr(m_CurrentIsSmall ? "s" : "S"));
    m_CharKeys[22].setText(tr(m_CurrentIsSmall ? "d" : "D"));
    m_CharKeys[23].setText(tr(m_CurrentIsSmall ? "f" : "F"));
    m_CharKeys[24].setText(tr(m_CurrentIsSmall ? "g" : "G"));
    m_CharKeys[25].setText(tr(m_CurrentIsSmall ? "h" : "H"));
    m_CharKeys[26].setText(tr(m_CurrentIsSmall ? "j" : "J"));
    m_CharKeys[27].setText(tr(m_CurrentIsSmall ? "k" : "K"));
    m_CharKeys[28].setText(tr(m_CurrentIsSmall ? "l" : "L"));

    // 第四排，以'z'起始的字母按键
    m_CharKeys[29].setText(tr(m_CurrentIsSmall ? "z" : "Z"));
    m_CharKeys[30].setText(tr(m_CurrentIsSmall ? "x" : "X"));
    m_CharKeys[31].setText(tr(m_CurrentIsSmall ? "c" : "C"));
    m_CharKeys[32].setText(tr(m_CurrentIsSmall ? "v" : "V"));
    m_CharKeys[33].setText(tr(m_CurrentIsSmall ? "b" : "B"));
    m_CharKeys[34].setText(tr(m_CurrentIsSmall ? "n" : "N"));
    m_CharKeys[35].setText(tr(m_CurrentIsSmall ? "m" : "M"));
}

Void_t VirtualKeyboard::updateInputValue()
{
    if (m_IsPwd)
    {
        QString display = "";
        Int32_t len = m_InputValue.length();
        for (Int32_t i = 0; i < len; ++i)
        {
            display += "*";
        }
        m_ValueLabel.setText(display);
    }
    else
    {
        m_ValueLabel.setText(m_InputValue);
    }
}

void VirtualKeyboard::onCharacterKeyDown(const GradientButton* pKey) //0~9、a~z这些键位，被按下时的响应函数
{
    // 获取已输入的长度
    Int32_t inputedLen = m_InputValue.length();

    // 检查是否长度有限制，且是否超长
    if ((VK_INPUT_INFI != m_InputMaxLen) && (inputedLen >= m_InputMaxLen))
    {
        return;
    }

    // 追加刚输入的东西
    m_InputValue += pKey->text();
    updateInputValue();

    // 发消息
    emit onInputChanged(m_InputValue);
}

void VirtualKeyboard::onShiftKeyDown(const GradientButton* pKey)
{
    if ((VK_ALLOW_SMALL_LETTER | VK_ALLOW_BIG_LETTER) != m_Case)
    {
        return; //如果不允许大小写切换，那么直接返回
    }

    m_CurrentIsSmall = !m_CurrentIsSmall;
    updateLetters();
}

void VirtualKeyboard::onBackSpaceKeyDown(const GradientButton* pKey)
{
    // 退格键的响应事件
    m_InputValue = m_InputValue.left(m_InputValue.size() - 1);
    updateInputValue();
    emit onInputChanged(m_InputValue);
}

void VirtualKeyboard::onClearKeyDown(const GradientButton* pKey) //清空键的响应事件
{
    // 清空键的响应事件
    m_InputValue = "";
    updateInputValue();
    emit onInputChanged(m_InputValue);
}

Void_t VirtualKeyboard::resetKeyBoard()
{
    m_Case = VK_ALLOW_BIG_LETTER | VK_ALLOW_SMALL_LETTER; //大小写限制
    m_IsPwd = Bool_false; //是否为密码
    m_InputMaxLen = VK_INPUT_INFI;
    m_InitValue = tr(""); //初始值
    m_InputValue = tr(""); //输入值
    m_FieldName = tr(""); //字段名
    m_CurrentIsSmall = Bool_true; //当前是否为小写
}

void VirtualKeyboard::onOK(const GradientButton* pKey)
{
    // 给调用者发消息，告知输入完毕
    emit onInputFinish(m_InputValue);

    // 关闭模式对话框
    close();
}

void VirtualKeyboard::onCancel(const GradientButton* pKey)
{
    // 给调用者发消息，告知输入完毕
    emit onInputCancel(m_InitValue);

    // 关闭模式对话框
    close();
}

VirtualKeyboard::~VirtualKeyboard()
{ }
